﻿angular.module('app.controllers', ['ngCookies']);


angular.module('app.filters', [])
  .filter('fromNow', function () {
      return function (date) {
          return moment(date).fromNow();
      }
  });



angular.module('app.directives', [])
    .directive('uiShift', [
        '$timeout', function ($timeout) {
            return {
                restrict: 'A',
                link: function (scope, el, attr) {
                    // get the $prev or $parent of this el
                    var _el = $(el),
                        _window = $(window),
                        prev = _el.prev(),
                        parent,
                        width = _window.width();

                    !prev.length && (parent = _el.parent());

                    function sm() {
                        $timeout(function () {
                            var method = attr.uiShift;
                            var target = attr.target;
                            _el.hasClass('in') || _el[method](target).addClass('in');
                        });
                    }

                    function md() {
                        parent && parent['prepend'](el);
                        !parent && _el['insertAfter'](prev);
                        _el.removeClass('in');
                    }

                    (width < 768 && sm()) || md();

                    _window.resize(function () {
                        if (width !== _window.width()) {
                            $timeout(function () {
                                (_window.width() < 768 && sm()) || md();
                                width = _window.width();
                            });
                        }
                    });
                }
            };
        }
    ])
    .directive('uiToggleClass', [
        '$timeout', '$document', function ($timeout, $document) {
            return {
                restrict: 'AC',
                link: function (scope, el, attr) {
                    el.on('click', function (e) {
                        e.preventDefault();
                        var classes = attr.uiToggleClass.split(','),
                            targets = (attr.target && attr.target.split(',')) || Array(el),
                            key = 0;
                        angular.forEach(classes, function (_class) {
                            var target = targets[(targets.length && key)];
                            (_class.indexOf('*') !== -1) && magic(_class, target);
                            $(target).toggleClass(_class);
                            key++;
                        });
                        $(el).toggleClass('active');

                        function magic(_class, target) {
                            var patt = new RegExp('\\s' +
                                _class.
                                replace(/\*/g, '[A-Za-z0-9-_]+').
                                split(' ').
                                join('\\s|\\s') +
                                '\\s', 'g');
                            var cn = ' ' + $(target)[0].className + ' ';
                            while (patt.test(cn)) {
                                cn = cn.replace(patt, ' ');
                            }
                            $(target)[0].className = $.trim(cn);
                        }
                    });
                }
            };
        }
    ])
    .directive('uiScroll', [
        '$location', '$anchorScroll', function ($location, $anchorScroll) {
            return {
                restrict: 'AC',
                link: function (scope, el, attr) {
                    el.on('click', function (e) {
                        $location.hash(attr.uiScroll);
                        $anchorScroll();
                    });
                }
            };
        }
    ])
    .directive('uiButterbar', [
        '$rootScope', '$anchorScroll', function ($rootScope, $anchorScroll) {
            return {
                restrict: 'AC',
                template: '<span class="bar"></span>',
                link: function (scope, el, attrs) {
                    el.addClass('butterbar hide');
                    scope.$on('$stateChangeStart', function (event) {
                        $anchorScroll();
                        el.removeClass('hide').addClass('active');
                    });
                    scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {
                        event.targetScope.$watch('$viewContentLoaded', function () {
                            el.addClass('hide').removeClass('active');
                        })
                    });
                }
            };
        }
    ])
    .directive('setNgAnimate', [
        '$animate', function ($animate) {
            return {
                link: function ($scope, $element, $attrs) {
                    $scope.$watch(function () {
                        return $scope.$eval($attrs.setNgAnimate, $scope);
                    }, function (valnew, valold) {
                        $animate.enabled(!!valnew, $element);
                    });
                }
            };
        }
    ])
    /**
     * A generic confirmation for risky actions.
     * Usage: Add attributes: ng-really-message="Are you sure"? ng-really-click="takeAction()" function
     */
    .directive('ngReallyClick', [
        function () {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    element.bind('click', function () {
                        var message = attrs.ngReallyMessage;
                        if (message && confirm(message)) {
                            scope.$apply(attrs.ngReallyClick);
                        }
                    });
                }
            }
        }
    ])
    /*
     * Usage: ng-compile='htmlGotFromServer'
     */
    .directive('ngCompile', [
        '$compile',
        function ($compile) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    scope.$watch(
                        function (scope) {
                            // watch the 'compile' expression for changes
                            return scope.$eval(attrs.ngCompile);
                        },
                        function (value) {
                            // when the 'compile' expression changes
                            // assign it into the current DOM
                            element.html(value);
                            if (angular.isDefined(value) === false || value === '') return;
                            // compile the new DOM and link it to the current
                            // scope.
                            // NOTE: we only compile .childNodes so that
                            // we don't get into infinite loop compiling ourselves
                            $compile(element.contents())(scope);
                        }
                    );
                }
            };
        }
    ])
    /**
     * Bind file from input to model
     * Usage: ng-file-model='a model in $scope'
     */
    .directive('ngFileModel', [
        function () {
            return {
                scope: {
                    ngFileModel: '='
                },
                link: function (scope, element, attributes) {
                    element.bind('change', function (changeEvent) {
                        var reader = new FileReader();
                        reader.onload = function (loadEvent) {
                            scope.$apply(function () {
                                scope.ngFileModel = {
                                    lastModified: changeEvent.target.files[0].lastModified,
                                    lastModifiedDate: changeEvent.target.files[0].lastModifiedDate,
                                    name: changeEvent.target.files[0].name,
                                    size: changeEvent.target.files[0].size,
                                    type: changeEvent.target.files[0].type,
                                    data: loadEvent.target.result
                                };
                                scope.ngFileModel.ext = scope.ngFileModel.name.substring(scope.ngFileModel.name.lastIndexOf('.'));
                            });
                        }
                        reader.readAsDataURL(changeEvent.target.files[0]);
                    });
                }
            }
        }
    ])
    /**
     * Set the target to stay in the middle of screen
     * Usage: ng-position-middle
     */
    .directive('ngPositionMiddle',[
        '$window',
        function($window) {
            return {
                replace: false,
                link: function(scope, iElm, iAttrs, controller) {
                    var height = $window.innerHeight - 44 - 49 - iElm[0].offsetHeight;
                    if (height >= 0) {
                        iElm[0].style.top = (height / 2 + 44) + 'px';
                    } else {
                        iElm[0].style.top = 44 + 'px';
                    }
                }
            }
        }
    ])    
    ;


angular.module('app.services', ['ngCookies','base64'])
    .factory('oauthService',['$http', '$q', '$cookies', '$base64', 'APP_CONFIG',
            function($http, $q, $cookies, $base64, APP_CONFIG) {
                var oauth = {
                    access_token: '',
                    token_type: '',
                    expiresAt: 0 //s
                };
                var clientId = 'fghaeth0934u51tjuydxzs38y289836';
                var clientSecret = '673fd777898013849760f56nmoidfnyi7je';
                var service = {};

                /*
                * current time, unit: ms
                */
                function getTime() {
                    return new Date().getTime();
                }

                /*
                * form url and endcode
                */
                function formUrlEncode(obj) {
                    var str = [];
                    for (var p in obj)
                        str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
                    return str.join('&');
                }

                // load from cookies
                var cookieAuth = $cookies.getObject(APP_CONFIG.tokenCookieKey);
                if (angular.isDefined(cookieAuth)) {
                    oauth = cookieAuth;
                }

                /*
               * generate Basic Authentication header
               */
                function getBasicAuthentication() {
                    var headerValue = 'Basic ' + $base64.encode(clientId + ':' + clientSecret);
                    return {
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'Authorization': headerValue
                    };
                }

                /*
                    * return token if it's valid, otherwise return null
                    */
                service.getToken = function() {
                    if (angular.isDefined(oauth) && oauth.expiresAt > getTime()) {
                        return oauth;
                    }
                    console.error('access token is expired or not exist');
                    return undefined;
                };

                function saveToken(tokenResult) {
                    oauth.access_token = tokenResult.access_token;
                    oauth.token_type = tokenResult.token_type === 'basic' ? 'Basic' : tokenResult.token_type === 'bearer' ? 'Bearer' : tokenResult.token_type;
                    oauth.expiresAt = getTime() + tokenResult.expires_in * 1e3;
                    $cookies.putObject(APP_CONFIG.tokenCookieKey, oauth);
                    console.log('saved token to cookies');
                }

                /*
                * basic token of client. must resovle.
                */
                service.getBasicTokenAsync = function() {
                    var defer = $q.defer();
                    var clientTokenConfig = {
                        method: 'POST',
                        url: '/Token',
                        headers: getBasicAuthentication(),
                        transformRequest: formUrlEncode,
                        data: { grant_type: 'client_credentials' }
                    };
                    $http(clientTokenConfig)
                        .success(function(result) {
                            saveToken(result);
                            defer.resolve({ success: true });
                        })
                        .error(function(err) {
                            console.error('get client token failed.');
                            console.error(err);
                            defer.resolve({ success: false, error: err });
                        });

                    return defer.promise;
                };


                /*
                * get user's token when got authorization token from sso 
                * must resolve
                */
                service.getUserTokenAsync = function(userName, password, openId) {
                    var defer = $q.defer();
                    if (userName === '' && password === '') {
                        //try to get token from cookies first when password is empty
                        if (angular.isDefined(service.getToken())) {
                            defer.resolve({ success: true });
                            return defer.promise;
                        }
                    }
                    var headers = getBasicAuthentication();
                    headers[APP_CONFIG.openIdHeaderName] = openId || '';
                    var clientTokenConfig = {
                        method: 'POST',
                        url: '/Token',
                        headers: headers,
                        transformRequest: formUrlEncode,
                        data: {
                            'grant_type': 'password',
                            'username': userName,
                            'password': password
                        }
                    };
                    $http(clientTokenConfig)
                        .success(function(result) {
                            saveToken(result);
                            defer.resolve({ success: true });
                        })
                        .error(function(err) {
                            defer.resolve({ success: false, error: err.error_description || '用户名或者密码错误' });
                            console.error(err);
                        });
                    return defer.promise;
                };

                /*
                * clear the authorization
                */
                service.clearCookies = function() {
                    $cookies.remove(APP_CONFIG.tokenCookieKey);
                }
                /*
                * loadToken when app started
                */
                service.loadTokenAsync = function() {
                    if (angular.isDefined(service.getToken())) {
                        var defer = $q.defer();
                        defer.resolve({ success: true });
                        return defer.promise;
                    }
                    return service.getBasicTokenAsync();
                };
                /*
                * logout
                */
                service.logoutAsync = function() {
                    var defer = $q.defer();
                    var headers = getBasicAuthentication();
                    var clientTokenConfig = {
                        method: 'POST',
                        url: '/api/Account/Logout',
                        headers: headers,
                        transformRequest: formUrlEncode
                    };
                    $http(clientTokenConfig)
                        .success(function(result) {
                            if (result.Code >= 0) {
                                service.clearCookies();
                                defer.resolve({ success: true });
                            } else defer.resolve({ success: false, error: result.Message });
                        }).error(function(x) {
                            defer.reject('注销异常');
                            console.error(x);
                        });
                    return defer.promise;
                };

                return service;
            }
    ])
    .factory('appInterceptor',[
        '$rootScope', '$q', '$cookies','APP_CONFIG',
      function ($rootScope, $q, $cookies, APP_CONFIG) {
        var isLogin = true;

        function startWith(str, start) {
            return str.substring(0, start.length) === start;
        }

        function isAbsolute(url) {
            return startWith(url, 'http://') || startWith(url, 'https://');
        }

        function getTime(time) {
            return (time || new Date()).getTime();
        }

        /**
         * 将Api请求指向Api服务器Host
         * @param {} config 
         * @returns {} 
         */
        function isApiRequest(config) {
            var isApi = false;
            if (!isAbsolute(config.url)) {
                //相对地址
                isApi =config.method==='POST'|| startWith(config.url, APP_CONFIG.apiPrefix);
            }
            if (isApi) {
                config.url = APP_CONFIG.apiHost + config.url;
            }
            return isApi;
        }

        var oauth = undefined;

        function getToken() {
            oauth = oauth || $cookies.getObject(APP_CONFIG.tokenCookieKey);
            if (angular.isDefined(oauth) && oauth.expiresAt > getTime()) {
                return oauth.token_type + ' ' + oauth.access_token;
            }
            return '';
        }

        function sayNotLogin() {
            if (isLogin) {
                isLogin = false;
                $rootScope.$emit(APP_CONFIG.eventUserNotLogin, 'notLogin');
            }
        }
        
        return {
            request: function(config) {
                //add authorization header except token request
                if (isApiRequest(config)) {
                    if (angular.isDefined(config.headers.Authorization) === false) {
                        var token = getToken();
                        if (token === '') {
                            sayNotLogin();
                            return $q.reject(config);
                        }
                        config.headers.Authorization = token;
                    }
                }
                $rootScope.delayLoading++;
                return config;
            },
            response: function(response) {
                $rootScope.delayLoading--;
                //!isLogin && (isLogin = true);
                return response;
            },
            responseError: function(response) {
                $rootScope.delayLoading--;
                $rootScope.$emit(APP_CONFIG.eventHttpError, response.status);
                return $q.reject(response);
            }
        };
    }
    ])
    .factory('alertService',[
        '$ionicPopup',
           function ($ionicPopup) {
               var service = {};

               service.add = function(msg, title, type) {
                   var alertPopup = $ionicPopup.alert(
                       {
                           title: title || '系统提示',
                           template: msg,
                           okText: '确定',
                           okType: type === 'success' ? 'button-balance' : 'button-assertive'
                       });
               };

               service.error = function(errMsg) {
                   service.add(errMsg);
               };
               return service;
           }
    ])
    .factory('accountService',[
        '$http', '$q', '$localStorage',
        function ($http, $q, $localStorage) {
            var service = { user: undefined };
            $localStorage.currentUser = undefined;
            
            /*
             * request user's profile
             */
            service.getUserDataAsync = function () {
                var defer = $q.defer();
                
                var savedUser = service.getLocalUserData();

                if(angular.isDefined(savedUser)){
                     defer.resolve({success:true,data:service.user} );
                }
                else{
                    $http.get('/api/account/userInfo')
                        .success(function (result) {
                            if (result.Code >= 0) {
                                $localStorage.currentUser=service.user = result.Data;
                                defer.resolve({success:true,data:service.user} );
                            } else {
                                defer.resolve({success:false,error:result.Message} );
                            }
                        })
                        .error(function (x) {
                            defer.resolve({success:false,error:'查询用户信息失败'} );
                            console.log(x);
                        });
                }
                return defer.promise;
            }
            /*
             * local user data saved in cookie when logined
             */
            service.getLocalUserData = function () {
                if (angular.isDefined(service.user)) {
                    return service.user;
                }
                return service.user = $localStorage.currentUser;
            };


            service.isInRole = function (roles) {
                var user = service.getLocalUserData();
                if (!angular.isDefined(user)) return false;
                if (user.Roles.indexOf('Admin') >= 0) return true;
                if (angular.isArray(roles) === false) {
                    roles = [roles];
                }
                for (var i = 0; i < roles.length; i++) {
                    if (user.Roles.indexOf(roles[i]) >= 0) return true;
                }
                return false;
            };

            service.getCounty = function () {
                var user = service.getLocalUserData();
                return {
                    CountyId: user.CountyId,
                    CountyName: user.CountyName
                };
            };
            service.getDistrict = function () {
                var user = service.getLocalUserData();
                return {
                    DistrictId: user.DistrictId,
                    DistrictName: user.DistrictName
                }
            };

            service.updateUser = function (newData) {
                angular.extend(service.user, newData);
                $localStorage.currentUser = service.user;
            };
            return service;
        }
    ])
    ;
    
/**
 *  app启动时，从服务器获取动态配置数据
 */
angular.module('lazy-routing', ['ui.router'])
    .provider('lazyRouter', function ($stateProvider) {
 
        var urlCollection;
        
        var required='required';
        
        function buildResolves(object){
            for(var attr in object){
                if(attr=='resolve'){
                    var desObject=object['resolve'][required];
                    if(desObject==null) continue;
                    var desFiles=angular.copy(desObject);
                    object['resolve'][required] = ['uiLoad',
                        function(uiLoad) {
                            return uiLoad.load(desFiles);
                        }];
                }else if(angular.isObject(object[attr])){
                    buildResolves(object[attr]);
                }
            }
        }
        
 
        this.$get = function ($http, $state) {
            return {
                setUpRoutes: function () {
                    $http.get(urlCollection).success(function (collection) {
                        for (var routeName in collection) {
                            if (!$state.get(routeName)) {
                                buildResolves(collection[routeName]);
                                $stateProvider.state(routeName, collection[routeName]);
                            }
                        }
                    });
                }
            }
        };
 
        this.setCollectionUrl = function (url) {
            urlCollection = url;
        }
    })
 
    .run(function (lazyRouter) {
        lazyRouter.setUpRoutes();
    });